package au.org.arcs.dss.client.tds.imos.dataset;

import java.util.*;
import java.io.*;

import thredds.crawlabledataset.*;

import au.org.arcs.dss.provider.DataSetServiceDelegate;
import au.org.arcs.dss.provider.dataset.DataSet;
import au.org.arcs.dss.provider.ConfigManager;
import au.org.arcs.dss.client.tds.utils.SystemUtils;
import au.org.arcs.dss.provider.DataSetServiceDelegateFactory;

/**
 *
 * @author ming
 */
public class CrawlableDataSetIMOSImpl extends CrawlableDatasetFile {
  public static final String CATALOG_FILE_NAME = "catalog.xml";
  private Object configObj;
  private DataSet dataSet;
  private static DataSetServiceDelegate dataSetServiceDelegate;

  public CrawlableDataSetIMOSImpl() {
    super(ConfigManager.getConfigManagerInstance().getTempFileFolder(), null);

    this.configObj = null;
    dataSetServiceDelegate = DataSetServiceDelegateFactory.getDataSetServiceDelegate();
  }

  public CrawlableDataSetIMOSImpl(DataSet dataSet) {
    this();
    this.dataSet = dataSet;
  }

  private CrawlableDataSetIMOSImpl(CrawlableDataSetIMOSImpl parent, String childPath ) {
    this();

    if (!childPath.contains(CATALOG_FILE_NAME)) {
      this.dataSet = dataSetServiceDelegate.getDescendant(parent.getDataSet(), childPath);
    } else {
      this.dataSet = new DataSet();

      // Remove catalog.xml
      if (childPath.equals(CATALOG_FILE_NAME)) {
        childPath = childPath.substring( 0, childPath.length()- CATALOG_FILE_NAME.length() );
      } else {
        childPath = childPath.substring( 0, childPath.length()- (CATALOG_FILE_NAME.length() + 1) );
      }

      this.dataSet.setPath(parent.getPath() + "/" + childPath);
      this.dataSet.setName(CATALOG_FILE_NAME);
      this.dataSet.setDirectory(false);
      this.dataSet.setFile(true);
      
      DataSet parentDataSet = parent.getDataSet();
      this.dataSet.setParent(parentDataSet);
    }
  }

  /**
   * The path is ignored since we don't look at local hard disk.
   */
  public CrawlableDataSetIMOSImpl( String path, Object configObj ) {
    this();

    if ( configObj != null ) {
      this.configObj = configObj;
    } else {
      this.configObj = null;
    }

    //String[] keyWithPath = SystemUtils.getPathKey(path);

    //ConfigManager.setRootPath(keyWithPath[0], keyWithPath[1]);

    if (ConfigManager.getConfigManagerInstance().isStub()) {
      this.dataSet = new DataSet();
      this.dataSet.setFile(false);
      this.dataSet.setDirectory(true);
      this.dataSet.setName("root");
      this.dataSet.setPath("/root");
      this.dataSet.setLastModified(1000);
      this.dataSet.setLength(100);
    } else {
      this.dataSet = dataSetServiceDelegate.getDataSet(path);
    }
  }

  @Override
  public Object getConfigObject() {
    return configObj;
  }

  @Override
  public String getPath() {
    return this.getDataSet().getPath();
  }

  @Override
  public String getName() {
    return this.getDataSet().getName();
  }

  @Override
  public CrawlableDataset getParentDataset() {
    DataSet parentDataSet = this.dataSet.getParent();

    if ( parentDataSet == null ) {
      return new CrawlableDataSetIMOSImpl( this.dataSet );
    }

    return new CrawlableDataSetIMOSImpl(parentDataSet);
  }

  @Override
  public boolean exists() {
    if (dataSet != null) {
      return true;
    }

    return false;
  }

  @Override
  public boolean isCollection() {
    return dataSet.isDirectory();
  }

  @Override
  public CrawlableDataset getDescendant(String relativePath) {
    if ( relativePath.startsWith( "/" ) ) {
      throw new IllegalArgumentException( "Path must be relative <" + relativePath + ">." );
    }

    return new CrawlableDataSetIMOSImpl(this,  relativePath);
  }

  @Override
  public List<CrawlableDataset> listDatasets() throws IOException {
    if ( ! this.exists() ) {
      String tmpMsg = "This dataset <" + this.getPath() + "> does not exist.";
      ConfigManager.logger.error(ConfigManager.key + ": " + tmpMsg);
      throw new IllegalStateException( tmpMsg );
    }

    if ( ! this.isCollection() ) {
      String tmpMsg = "This dataset <" + this.getPath() + "> is not a collection dataset.";
      ConfigManager.logger.error(ConfigManager.key + ": " + tmpMsg);
      throw new IllegalStateException( tmpMsg );
    }

    List<CrawlableDataset> list = new ArrayList<CrawlableDataset>();
    List<DataSet> dataSets =  dataSetServiceDelegate.getDataSets(this.getDataSet());

    if ( dataSets == null ) {
      ConfigManager.logger.error( "listDatasets(): the underlying file [" + this.dataSet.getPath() + "] exists, is a directory, and canRead()==true but listFiles() returns null. This may be a problem Java has on Windows XP (Java 7 should fix).");
      return Collections.emptyList();
    }

    for (DataSet ds : dataSets ) {
      CrawlableDataSetIMOSImpl crDs = new CrawlableDataSetIMOSImpl( ds );
      if ( crDs.exists()) {
        list.add( crDs );
      }
    }

    return list;
  }

  @Override
  public List<CrawlableDataset> listDatasets(CrawlableDatasetFilter filter) throws IOException {

    List<CrawlableDataset> list = this.listDatasets();

    if ( filter == null ) return list;
    List<CrawlableDataset> retList = new ArrayList<CrawlableDataset>();

    for ( CrawlableDataset curDs: list ) {
      if ( filter.accept( curDs ) ) {
        retList.add( curDs );
      }
    }

    return ( retList );
  }

  @Override
  public long length() {
    return dataSet.getLength();
  }

  @Override
  public Date lastModified() {
    return new Date(dataSet.getLastModified());
  }

  @Override
  public File getFile() {
    return this.getDataSet().getFileObject();
  }

  /**
   * @return the dataSet
   */
  public DataSet getDataSet() {
    return dataSet;
  }

  /**
   * @param dataSet the dataSet to set
   */
  public void setDataSet(DataSet dataSet) {
    this.dataSet = dataSet;
  }
}